class Vue {
    constructor(options) {
        //保存选项
        this.$options = options;
        //通过选择器获取渲染的目标DOM元素
        this.$el = document.querySelector(options.el);
        //把选项里的data属性赋值给Vue实例的$data属性 
        this.$data = options.data;
        //初始化
        this.init();
    }
    init() {
        //数据代理 vm.msg = options.data.msg
        this.proxyData();
        this.compile();
    }
    //数据代理 使得this.msg 等价于this.$data.msg
    proxyData() {
        //遍历this.$data上的所有的属性
        for (let key in this.$data) {
            //vm.msg  this[key]
            Object.defineProperty(this, key, {
                get() {//从Vm实例上取值的会去Vm实例上的$data属性上取值
                    return this.$data[key];
                },
                set(newVal) {//给vm实例赋值的时候会把值赋给vm实例的$data对象上
                    this.$data[key] = newVal;
                    this.compile();
                }
            })
        }
    }
    //编译模板
    compile() {
        //获取模板内容
        const { template } = this.$options;
        //转换模板，用正则替换,找到{{msg}},变成this.msg=hello
        const html = template.replace(/\{\{(.+?)\}\}/g, (_, key) => {
            return this[key];
        });
        //创建一个类型为div的临时容器
        const tempContainer = document.createElement('div');
        //把转换成的html变成临时容器的innerHTML，这样就可以在内存里得到span真实DOM
        tempContainer.innerHTML = html;
        //在临时容器中寻找拥有v-text属性的DOM元素
        const hasVTexts = tempContainer.querySelectorAll('[v-text]');
        if (hasVTexts && hasVTexts.length > 0) {
            for (const hasVText of hasVTexts) {
                //获取此DOM元素上的v-text属性的值
                let textBinding = hasVText.getAttribute('v-text');//msg
                //给此DOM元素的文本属性赋值为此实例的变量属性this=vm textBing=msg vm.msg
                hasVText.textContent = this[textBinding];
            }
        }
        //在临时容器中寻找拥有v-html属性的DOM元素
        const hasVHTMLs = tempContainer.querySelectorAll('[v-html]');
        if(hasVHTMLs && hasVHTMLs.length>0){
            for(const hasVHTML of hasVHTMLs){
                let htmlBinding = hasVHTML.getAttribute('v-html');
                hasVHTML.innerHTML = this[htmlBinding];//vm.msg
            }
        }
        //获取的是临时容器的第一个儿子
        const newEl = tempContainer.firstChild;
        //然后就可以把第一个儿子，也就是span替换掉老的el
        document.body.replaceChild(newEl, this.$el)
        //渲染完成后把此新的el赋给this.$el,成为下一次被更新DOM元素
        this.$el = newEl;
    }
}